package model.PokerTP;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

import com.sun.org.apache.bcel.internal.generic.NEW;

import model.messages.*;
import scala.concurrent.Await;
import scala.concurrent.Future;
import scala.concurrent.duration.Duration;
import akka.actor.ActorRef;
import akka.actor.UntypedActor;
import akka.pattern.Patterns;
import akka.util.Timeout;


public class ActorLicytacja extends UntypedActor{
    private int[] tzakladow;//kto ile dorzuci� do puli 
    public int zaklad=0;//ca�a pula 
    public int kolej;//kto obstawia
    public int max=1;//najwy�sze obstawienie
    public boolean inited = false;
    Player[] gracze;
    ActorRef[] actors;
    ActorTable table;
    int g;//liczba graczy 
    ActorLicytacja() {}
    
    ActorLicytacja(List<ActorRef> actors, ActorTable table) {
    	init(actors, table);
    }
    //nowe rozdanie
    ActorLicytacja(Player[] gracze,int g){
        tzakladow=new int[g];
        for(int i=0;i<g;i++){
            tzakladow[i]=0;
        }
        this.gracze=gracze;
        this.g=g;
    }
    
    void init(List<ActorRef> actors, ActorTable table) {
    	if(actors == null || table == null) {
    		throw new NullPointerException();
    	}
    	this.table = table;
    	gracze = new Player[actors.size()];
    	for(int i = 0; i < actors.size(); ++i) {
    		Player p = getPlayerByActorRef(actors.get(i));
    		if(p == null) {// spróbuj jeszcze raz
    			p = getPlayerByActorRef(actors.get(i));
    			if(p == null)
    				continue;
    		}
    		gracze[i] = p;
    	}
    	g = gracze.length;
    	tzakladow=new int[g];
        for(int i=0;i<g;i++){
            tzakladow[i]=0;
        }
        this.actors = actors.toArray(new ActorRef[actors.size()]);
        kolej = 0;
    	inited = true;
    }
    //nowe rozdanie wpisowe
    public void Wpisowe(int a){
        for(int i=0;i<g;i++){
            if(gracze[i].cash>5){
                zaklad+=a;
                gracze[i].cash-=a;
            }else
                tzakladow[i]=-2;
        }
        Random gen = new Random();
        kolej=gen.nextInt(g);
        System.out.println( "Pula"+" "+zaklad);
    }
    //ka�da licytacja
    public void Lic(){
        System.out.println( "Pula"+" "+zaklad+" "+gracze[kolej].getNazwa()+" "+gracze[kolej].cash);
        
        while(cmp()==1){
            
            if(gracze[kolej].cash<=-1){
                kolej=(kolej+1)%g;
            }
            
            // Wysyła informację do gracza o jego kolejce i czeka na odpowiedź (przez maksymalnie PokerGlobalSettings.waitForResponseTime
            Timeout timeout = new Timeout(Duration.create(PokerGlobalSettings.waitForResponseTime, TimeUnit.MINUTES));
        	Future<Object> future = Patterns.ask(actors[kolej], new TablePopupMessageBidding("Twoja kolej."), timeout);
        	PlayerBiddingAction pba = null;
        	try {
        		pba = (PlayerBiddingAction) Await.result(future, Duration.create(PokerGlobalSettings.waitForResponseTime, TimeUnit.MINUTES));
        	} catch(Exception e) {
        		continue;
        	}
            if(pba == null) {
            	pba = new PlayerBiddingAction(PlayerBiddingAction.BiddingAction.FOLD, actors[kolej], null);
            }
        	/*
            switch(gracze[kolej].licytuj()){
                case "check":
                        if(check(gracze[kolej],kolej)==1){
                            kolej=(kolej-1)%g;
                            System.out.println("nie mo�na");
                        }else{
                            System.out.println(gracze[kolej].getNazwa()+" gracz czeka");
                        }
                        
                        break;
                case "bet":
                        if(bet(gracze[ kolej],kolej)==0){
                            kolej=(kolej-1)%g;
                            System.out.println("nie mo�na");
                        }
                        break;
                case "raise":
                        if(raise(gracze[ kolej], kolej)==1){
                            
                            System.out.println("All-in");
                        }
                        break;
                case "call":  
                        if(call(gracze[kolej],kolej)==1){
                            System.out.println("All-in");
                        }
                        break;
                case "fold":
                       fold(gracze[kolej],kolej);
                        break;
                default :
                        kolej=(kolej-1)%g;
                        System.out.println("z�y wyb�r");
                        break;
            }*/
            switch(pba.biddingAction) {
            case CHECK:
            	if(check(gracze[kolej],kolej)==1){
                    kolej=(kolej-1)%g;
                    actors[kolej].tell(new TablePopupMessage("Nie można wykonać tej akcji."), getSelf()); 
                }else{
                	table.notifyAll(new TableMessage("czeka", gracze[kolej].getNazwa()));
                }
                break;
            case BET:
            	if(bet(gracze[ kolej],kolej)==0){
                    kolej=(kolej-1)%g;
                    actors[kolej].tell(new TablePopupMessage("Nie można wykonać tej akcji."), getSelf());
                }
                break;
            case RAISE:
            	if(raise(gracze[ kolej], kolej)==1){
            		table.notifyAll(new TableMessage("zagrał All-in", gracze[kolej].getNazwa()));
                }
                break;
            case FOLD:
            	fold(gracze[kolej],kolej);
                break;
            default:
            	kolej=(kolej-1)%g;
            	actors[kolej].tell(new TablePopupMessage("Nie można wykonać tej akcji."), getSelf());
                break;
            }
            kolej=(kolej+1)%g;
            //System.out.println( "Pula"+" "+zaklad+" "+gracze[kolej].getNazwa()+" "+gracze[kolej].cash);
            table.notifyAll(new TableMessage("obecna pula: " + zaklad, gracze[kolej].getNazwa()));
        }
    }   
    public int check(Player a,int kolej){
        
        if(max>1){
            return 1;
        }
        return 0;
    }
    public int bet(Player a,int kolej){
       //System.out.println("o ile");
       int tmp=0;
            if(max==1){
                //tmp=a.ile();
            	tmp = getNumberFromActor(actors[kolej], new NeedInputData("Podaj kwotę:", "ile"));
                System.out.println(tmp);
                if (tmp>1&&tmp<a.cash){
                    max=tmp;
                    a.cash-=tmp;
                    tzakladow[kolej]=tmp;
                    zaklad=zaklad+tmp;
                    return 1;
                }else if(tmp==a.cash){
                    return all(a,kolej);
                }else
                    return 0;
            }else
                return 0;
        
    }
    public int raise(Player a, int kolej){
        //System.out.println("o ile");
        int tmp=0;
        //tmp=a.ile();
        tmp = getNumberFromActor(actors[kolej], new NeedInputData("Podaj kwotę:", "ile"));
        if(call(a,kolej)==0){
            if(max+tmp<a.cash){
                tzakladow[kolej]+=tmp;
                max+=tmp;
                zaklad+=tmp;
                return 0;
            }else
                return all(a, kolej);
        }else
            return 1;
        
    }
    public int call(Player a, int kolej){
        if(max-tzakladow[kolej]>=a.cash){
            return all(a,kolej);
        }else{
            zaklad+=max-tzakladow[kolej];
            a.cash-=max-tzakladow[kolej];
            tzakladow[kolej]=max;
            return 0;
        }
    }
    public int all(Player a,int kolej){
        zaklad+=a.cash;
        a.cash=0;
        tzakladow[kolej]=-1;
        
        return 1;
    }
    
    public void fold(Player a, int kolej){
        tzakladow[kolej]=-2;
    }
    public void pulatoString(){
        System.out.println( "Pula"+" "+zaklad);
    }
    public int cmp(){
        int b=0;
        for(int i=0;i<g;i++){
            if(tzakladow[i]==max||tzakladow[i]<=-1){
                b=0;
            }else
                return 1;
        }
        return b;
    }
    public void wplata(Player a){
        a.cash+=zaklad;
    }
    
    private Player getPlayerByActorRef(ActorRef act) {
    	Timeout timeout = new Timeout(Duration.create(PokerGlobalSettings.waitForResponseTime, TimeUnit.MINUTES));
    	Future<Object> future = Patterns.ask(act, new GetPlayerObject(), timeout);
    	PlayerObject player = null;
    	try {
    		player = (PlayerObject) Await.result(future, Duration.create(PokerGlobalSettings.waitForResponseTime, TimeUnit.MINUTES));
    	} catch(Exception e) {
    		return null;
    	}
    	if(player != null) {
    		return player.player;
    	} else {
    		return null;
    	}
    }
	@Override
	public void onReceive(Object message) throws Exception {
		// TODO Automatycznie generowany szkielet metody
		if(message instanceof LicytacjaInit) {
			LicytacjaInit data = (LicytacjaInit)message;
			init(data.actors, data.table);
		}
		else if(message instanceof PlayerBiddingAction) {
			
		} 
		else {
			unhandled(message);
		}
	}
	
	private int getNumberFromActor(ActorRef actor, Object message) throws NumberFormatException {
		Timeout timeout = new Timeout(Duration.create(30, TimeUnit.SECONDS));
    	Future<Object> future = Patterns.ask(actor, message, timeout);
    	RequestedData recieved = null;
    	Integer i = null;
    	try {
    		recieved = (RequestedData)Await.result(future, Duration.create(PokerGlobalSettings.waitForResponseTime, TimeUnit.SECONDS));
    	} catch(Exception e) {
    		return 0;
    	}
    	if(recieved.data instanceof Integer) i = (Integer)recieved.data;
    	else i = Integer.parseInt(recieved.data.toString());
    	return i;
	}
}